package 
{
	import flash.utils.ByteArray;
	import flash.utils.IDataOutput;
	import flash.utils.getQualifiedClassName;
	
	import org.musince.logic.ISerializable;

	public class Protocol
	{
		public const TYPE_INT:int = 0;
		public const TYPE_STRING:int = 1;
		public const TYPE_OBJECT:int = 2;
		public const TYPE_INT_ARRAY:int = 3;
		public const TYPE_STRING_ARRAY:int = 4;
		public const TYPE_OBJECT_ARRAY:int = 5;
		public const TYPE_BYTE_ARRAY:int = 6;
		public const TYPE_LUA_TABLE:int = 7;
		public const TYPE_BYTE:int = 8;
		
						
		public var rpcs:Array = [
			{name:"registerAccount", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}]},
			{name:"challengeResult", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}, 
				{label:"enemyName", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}, 
				{label:"win", type:TYPE_BYTE}]},
			{name:"getPVPRank", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}]},
			{name:"getChallengeList", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}]},
			{name:"updatePlayer", args:[{label:"DataPlayer", type:TYPE_OBJECT, cls:DataPlayer}]},
			{name:"flushLog", args:[]},
			{name:"getBattlePlayer", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}]},
			{name:"getChallengeRecord", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}]},
			{name:"testNet", args:[]},
			{name:"setVersionMin", args:[{label:"version", type:TYPE_INT}]},
			{name:"updateState", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}, {label:"level", type:TYPE_INT}, {label:"stage", type:TYPE_INT}, {label:"subStage", type:TYPE_INT}, {label:"currentMainTask", type:TYPE_INT}]},
			{name:"refreshPet", args:[{label:"name", type:TYPE_STRING}, {label:"guid", type:TYPE_STRING}, {label:"quality", type:TYPE_INT}, {label:"nation", type:TYPE_INT}, {label:"profile", type:TYPE_INT}]},
			{name:"setServerList", args:[{label:"addr", type:TYPE_STRING_ARRAY}, {label:"port", type:TYPE_INT_ARRAY}, {label:"state", type:TYPE_INT_ARRAY}]}
		];
		
		public function writeHead(buf:IDataOutput, msg:String, rid:int):void {
			buf.writeUTF(msg);
			buf.writeInt(rid);
		}
		
		public function writeInt(buf:IDataOutput, v:int):void
		{
			buf.writeByte(TYPE_INT);
			buf.writeInt(v);
		}
		
		public function writeByte(buf:IDataOutput, v:int):void
		{
			buf.writeByte(TYPE_BYTE);
			buf.writeInt(v);
		}
		
		public function writeString(buf:IDataOutput, v:String):void
		{
			buf.writeByte(TYPE_STRING);
			buf.writeUTF(v);
		}
		
		public function writeObject(buf:IDataOutput, v:ISerializable):void
		{
			buf.writeByte(TYPE_OBJECT);
			var name:String =  getQualifiedClassName(v);
			name = name.substr(name.lastIndexOf("::") + 1);
			buf.writeUTF(name);
			v.serialize(buf);
		}
		
		public function writeType(buf:IDataOutput, v:Object):void
		{			
			if (v is int) {
				buf.writeByte(TYPE_INT);
				buf.writeInt(v as int);					
				return;
			}
			if (v is String) {
				buf.writeByte(TYPE_STRING);
				buf.writeUTF(v as String);
				return;
			}
			if (v is ISerializable) {
				buf.writeByte(TYPE_OBJECT);
				var name:String =  getQualifiedClassName(v);
				name = name.substr(name.lastIndexOf("::") + 1);
				buf.writeUTF(name);
				(v as ISerializable).serialize(buf);
				return;
			}
			if (v is ByteArray) {
				buf.writeByte(TYPE_BYTE_ARRAY);
				var bytes:ByteArray = v as ByteArray;
				buf.writeInt(bytes.length);
				bytes.position = 0;
				buf.writeBytes(bytes);
				return;
			}
		}
		
		public function writeRPC(buf:IDataOutput, name:String, args:Array):void {
			buf.writeUTF(name);
			if (args == null) {
				buf.writeByte(0);
				return;
			}
			var arg:Object;
			var type:int;
			var f:Function;
			buf.writeByte(args.length);
			for (var i:int = 0; i < args.length; i++)
			{
				arg = args[i];
				writeType(buf, arg);
			}
		}
	}
}